package com.jason.session;

import com.jason.config.Configuration;
import com.jason.config.MapperStatement;

import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Executor executor;

    private boolean autoCommit = false;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    public DefaultSqlSession(Configuration configuration, boolean autoCommit) {
        this.configuration = configuration;
        this.autoCommit = autoCommit;
    }


    @Override
    public <E> List<E> selectList(String statementId, Object...params) throws Exception {
        executor = new SimpleExecutor(this.autoCommit);
        return executor.query(this.configuration, getMapperStatement(statementId), params);
    }

    @Override
    public <T> T selectOne(String statementId, Object...params) throws Exception {
        List<Object> resultList = selectList(statementId, params);
        if (resultList != null && resultList.size() == 1) {
            return (T) resultList.get(0);
        }
        if (resultList != null && resultList.size() > 1) {
            throw new RuntimeException("查询数据返回结果接多余一条");
        }
        return null;
    }

    @Override
    public int insert(String statementId, Object... params) throws Exception {
        return update(statementId, params);
    }

    @Override
    public int update(String statementId, Object... params) throws Exception {
        executor = new SimpleExecutor(this.autoCommit);
        return executor.update(this.configuration, getMapperStatement(statementId), params);
    }

    @Override
    public int delete(String statementId, Object... params) throws Exception {
        return update(statementId, params);
    }

    @Override
    public <T> T getMapper(Class<T> classType) {
        T t = (T) Proxy.newProxyInstance(classType.getClassLoader(), new Class[] {classType}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String statementId = className + "." + methodName;
                MapperStatement mapperStatement = configuration.getMapperStatementMap().get(statementId);
                String operation = mapperStatement.getOperation();
                if (MapperStatement.SELECT.equals(operation)) {
                    Type type = method.getGenericReturnType();
                    if (type instanceof ParameterizedType)
                        return selectList(statementId, args);
                    else
                        return selectOne(statementId, args);
                } else if (MapperStatement.INSERT.equals(operation)){
                    return insert(statementId, args);
                } else if (MapperStatement.UPDATE.equals(operation)){
                    return update(statementId, args);
                } else {
                    return delete(statementId, args);
                }
            }
        });
        return t;
    }

    @Override
    public void close() throws SQLException {
        this.executor.close();
    }

    @Override
    public void setAutoCommit(boolean autoCommit) {
        this.autoCommit = autoCommit;
    }

    @Override
    public void commit() throws SQLException {
        this.executor.commit();
    }

    @Override
    public void rollBack() throws SQLException {
        this.executor.rollBack();
    }

    private MapperStatement getMapperStatement(String statementId) {
        MapperStatement mapperStatement = this.configuration.getMapperStatementMap().get(statementId);
        if (mapperStatement == null)
            throw new RuntimeException("取出mapperStatement异常，找不到mapperStatement");
        return mapperStatement;
    }
}
